package com.action.gulimall.ware.config;

import com.action.common.constant.MqConstant;
import com.action.gulimall.ware.entity.WareSkuEntity;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author sl shilun217@qq.com
 * @Deacription RabbitMQ自定义配置
 * @date 2021/07/04/11:58
 **/

@Slf4j
@Configuration
public class MyRabbitmqConfig {

    private RabbitTemplate rabbitTemplate;

    @Primary
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setMessageConverter(messageConverter());
        init();
        return rabbitTemplate;
    }
    //消息序列化机制 json格式序列化
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    //确认模式回调配置
    public void init(){
        //消息成功从生产者发送到borker后对应的回调
        rabbitTemplate.setConfirmCallback((correlationData,ack,cause)->{
            log.info("correlationData["+correlationData.toString()+"]==>ack["+ack+"]==>caise["+cause+"]");
        });
        //消息没有成功从交换机发送到对应的队列后对应的回调
        rabbitTemplate.setReturnCallback((message,replyCode,replyText,exchange,routingKey)->{
            log.info("message["+message.toString()+"]==>replyCode["+replyCode+"]==>replyText["+replyText+"]" +
                    "==>exchange["+exchange+"]==>routingKey["+routingKey+"]");
        });
    }

    //start------订单库存锁定释放相关
    @Bean
    public TopicExchange orderEventExchange(){
        //DirectExchange(String name, boolean durable, boolean autoDelete, Map<String, Object> arguments)
        return new TopicExchange(MqConstant.ORDER_EXCHANGE_NAME,true,false,null);
    }

    @Bean
    public Queue orderStockLockQueue(){
        //Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
        Map<String, Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange", MqConstant.ORDER_EXCHANGE_NAME);
        arguments.put("x-dead-letter-routing-key", MqConstant.ORDER_STOCK_RELEASE_ROUTINGKEY);
        arguments.put("x-message-ttl", MqConstant.ORDER_STOCK_LOCK_QUEUE_TTL); // 消息过期时间 1分钟
        return new Queue(MqConstant.ORDER_STOCK_LOCK_QUEUE_NAME,
                true,false,false,arguments);
    }

    @Bean
    public Queue orderStockReleaseQueue(){
        //Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
        return new Queue(MqConstant.ORDER_STOCK_RELEASE_QUEUE_NAME,
                true,false,false,null);
    }

    @Bean
    public Binding orderStockLockQueueBinding(){
        return new Binding(MqConstant.ORDER_STOCK_LOCK_QUEUE_NAME,
                Binding.DestinationType.QUEUE,
                MqConstant.ORDER_EXCHANGE_NAME,
                MqConstant.ORDER_STOCK_LOCK_BINGDINGKEY,
                null);
    }

    @Bean
    public Binding orderStockReleaseQueueBinding(){
        return new Binding(MqConstant.ORDER_STOCK_RELEASE_QUEUE_NAME,
                Binding.DestinationType.QUEUE,
                MqConstant.ORDER_EXCHANGE_NAME,
                MqConstant.ORDER_STOCK_RELEASE_BINGDINGKEY,
                null);
    }
    //end------订单库存锁定释放相关

    //配置对应的exchange、queue、binding
    @Bean
    public Queue testQueue(){
        //Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
        return new Queue("rabbitmq-queue-test",true,false,false,null);
    }

    @Bean
    public DirectExchange testExchange(){
        //DirectExchange(String name, boolean durable, boolean autoDelete, Map<String, Object> arguments)
        return new DirectExchange("rabbitmq-exchange-test",true,false,null);
    }

    @Bean
    public Binding getTestBinding(Queue testQueue,DirectExchange testExchange){
        return BindingBuilder.bind(testQueue).to(testExchange).with("rabbitmq-test-routingKey");
//        return new Binding("rabbitmq-queue-test",
//                Binding.DestinationType.QUEUE,
//                "rabbitmq-exchange-test",
//                "rabbitmq-test-routingKey",
//                null);
    }

    //@RabbitListener(queues={"rabbitmq-queue-test"})
    //@Configuration
    protected static class TestConsumer{

        @RabbitHandler
        public void handlerMessage(Message message,String content,Channel channel){
            log.info("handlerMessage收到消息为message["+message.getMessageProperties().getCorrelationId()+"],content["+content+"]");
            try{
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            }catch (IOException e) {
                log.error("手动确认消息出现异常,message="+message.toString(), e);
                //channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        }

        @RabbitHandler
        public void handlerEntityMessage(Message message, WareSkuEntity content, Channel channel){
            log.info("handlerEntityMessage收到消息为message["+message.getMessageProperties().getCorrelationId()+"]==>content"+content);
            try{
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            }catch (IOException e) {
                log.error("手动确认消息出现异常,message="+message.toString(), e);
                //channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        }
    }
}
